package cn.tj.wenda.cloud.security;

import cn.tj.wenda.cloud.entity.LoginUserInfo;

import java.util.Base64;
import java.util.Date;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;

public class JsonWebToken {
    private static Logger logger = LoggerFactory.getLogger(JsonWebToken.class);

    private static final String secretKey = "@WSde3%";
    private static final String splitter = ".";//拆分符

    /***
     * 建立新的JWT
     * @param loginUserInfo 用户信息
     * @param days jwt有效时间
     * @return
     */
    public static String createJwt(LoginUserInfo loginUserInfo, int days) {
        String jwtHead = "{\"typ\":\"JWT\",\"alg\":\"HS256\"}";

        JSONObject objPayload = new JSONObject();

        long currDate = getUnixTime(new Date());
        long expDate = currDate + ((long)days * 24L * 3600L);
        objPayload.put("iss", "");
        objPayload.put("iat", currDate);//token创建时间
        objPayload.put("aud", "");//接收该JWT的一方
        objPayload.put("sub", "");//该JWT所面向的用户
        objPayload.put("nbf", currDate);//该JWT生效时间,秒后生效
        objPayload.put("exp", expDate);//超期时间
        objPayload.put("jti", "");//JWT ID。针对当前token的唯一标识
        objPayload.put("usr",loginUserInfo);//载荷

        Base64.Encoder encoder = Base64.getEncoder();
        String claim;
        try {
            claim = encoder.encodeToString(jwtHead.getBytes("UTF-8")) + splitter + encoder.encodeToString(objPayload.toString().getBytes("UTF-8"));

            String signature = SHA256.getSignature(claim,secretKey);

            String jwt = claim + splitter + signature;
            return jwt;
        }
        catch(Exception e) {
        	logger.error("##### Token生成出错！ ",e);
        }
        return "";
    }

    /***
     *
     * @param jwt
     * @return 0=jwt正确可用，1=jwt格式不正确，2=jwt未生效，3=jwt已超期失效，4=jwt没有有效载荷
     */
    public static int checkJWT(String jwt) {
        String[] aryJwt = StringUtils.split(jwt, splitter);
        if(aryJwt.length != 3) return 1;//jwt格式不正确

        try {

            if(StringUtils.isEmpty(aryJwt[0]) || StringUtils.isEmpty(aryJwt[1]) || StringUtils.isEmpty(aryJwt[2])) return 1;//jwt格式不正确

            String claim = aryJwt[0] + splitter + aryJwt[1];

            String signature = SHA256.getSignature(claim,secretKey);

            if(!aryJwt[2].equals(signature)) return 1;//jwt格式不正确

            Base64.Decoder decoder = Base64.getDecoder();
            String jwtJson = new String(decoder.decode(aryJwt[1]), "UTF-8");

            JSONObject objPayload = JSONObject.parseObject(jwtJson);

            long currDate = getUnixTime(new Date());

            if(objPayload.getLong("nbf") > currDate) return 2;//该token未生效

            if(objPayload.getLong("exp") < currDate) return 3;//该token已超期失效

            if(objPayload.getJSONObject("usr") == null) return 4;//该token没有效载荷
        }
        catch(Exception e) {
            return 1;
        }

        return 0;
    }

    /**
     * 将JWT校验信息翻译为文字信息
     * @param checkVal 0=jwt正确可用，1=jwt格式不正确，2=jwt未生效，3=jwt已超期失效，4=jwt没有有效载荷
     * @return
     */
    public static String getCheckMsg(int checkVal) {
    	String msg = "";
    	switch(checkVal) {
    		case 1:
    			msg = "jwt格式不正确";
    			break;
    		case 2:
    			msg = "jwt未生效";
    			break;
    		case 3:
    			msg = "jwt已超期失效";
    			break;
    		case 4:
    			msg = "jwt没有有效载荷";
    			break;
    	}
    	return msg;
    }
    
    /***
     * 从JWT中取出当头用户信息
     * @param jwt
     * @return
     */
    public static LoginUserInfo getPayload(String jwt) {
        try {
            String payload = StringUtils.split(jwt, splitter)[1];
            Base64.Decoder decoder = Base64.getDecoder();
            String jwtJson = new String(decoder.decode(payload), "UTF-8");

            JSONObject objPayload = JSONObject.parseObject(jwtJson);
            JSONObject obj = objPayload.getJSONObject("usr");

            LoginUserInfo loginUserInfo = (LoginUserInfo) obj.toJavaObject(LoginUserInfo.class);

            return loginUserInfo;
        }
        catch(Exception e) {
        	logger.error("##### 从Token获取当前用户信息出错！ ",e);
            return null;
        }
    }


    private static long getUnixTime(Date date) {
        return date.getTime() / 1000;
    }
}
